package com.broada.apm.service.impl;

import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellRangeAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.broada.apm.ajax.IndicatorResult;
import com.broada.apm.ajax.MenuResult;
import com.broada.apm.ajax.PerformanceResult;
import com.broada.apm.base.BaseService;
import com.broada.apm.cache.IndicatorItemManager;
import com.broada.apm.entity.IndicatorItem;
import com.broada.apm.entity.MenuColumn;
import com.broada.apm.entity.ProtocolMenu;
import com.broada.apm.entity.Service;
import com.broada.apm.entity.TradeErrorDetail;
import com.broada.apm.model.ApplicationSystem;
import com.broada.apm.model.L7moduleMenu;
import com.broada.apm.model.PerformanceView;
import com.broada.apm.service.IndicatorService;
import com.broada.apm.utils.ExceptionUtils;

public class IndicatorServiceImpl extends BaseService implements IndicatorService {
	private static final Logger logger = LoggerFactory.getLogger(IndicatorServiceImpl.class);
	@Override
	public MenuResult queryMenus(String nodeId) {
		
		MenuResult result = new MenuResult();
		Service node = null;
		if (nodeId.contains("-")) {
			node = serverLogic.queryServiceById(nodeId);
		} else {
			node = serverLogic.queryDisServiceById(nodeId);
		}
		if (node == null) {
			result.setFailMessage("节点不存在");
		} else {
			List<ProtocolMenu> menus = indicatorLogic.queryProtocolMenus(node.getProtocol() == 0 ? node.getAutoDiscoveryProtocol() : node.getProtocol());
			result.setMenus(menus);
		}
		return result;
	}

	@Override
	public MenuResult queryMenuColumns(int menuId) {
		MenuResult result = new MenuResult();
		List<MenuColumn> columns = indicatorLogic.queryMenuColumns(menuId);
		result.setColmuns(columns);
		return result;
	}

	@Override
	public PerformanceResult queryMenuData(String applicationId, String agentId, int menuId, String dataKey, String dataId,
			String keyWord, long startDate, long endDate, String orderBy, boolean desc, int pageIndex, int pageSize) {
		PerformanceResult result = new PerformanceResult();
		if ("NaN".equals(endDate) || "NaN".equals(startDate)) {
			result.setFailMessage("查询时间错误");
			return result;
		}
		List<PerformanceView> perfs = null;
		if (endDate == 0)
			endDate = System.currentTimeMillis();
		if (startDate == 0)
			startDate = endDate - 60 * 60 * 1000;
		if (pageSize == 0)
			pageSize = 10;
		try {
			perfs = indicatorLogic.queryMenuData(applicationId, agentId, menuId, dataKey, dataId, keyWord, pageIndex, pageSize,
					startDate, endDate, orderBy, desc);
			result.pagingHandle(pageSize, pageIndex, perfs);
		} catch (Exception e) {
			result.setFailMessage(e.getMessage());
		}
		return result;
	}

	@Override
	public PerformanceResult queryTradeErrorCode(String appId, String nodeId, String keyWord, int pageIndex,
			int pageSize, long startDate, long endDate) {
		PerformanceResult result = new PerformanceResult();
		List<PerformanceView> page = null;
		if ("NaN".equals(endDate) || "NaN".equals(startDate)) {
			result.setFailMessage("查询时间错误");
			return result;
		}
		if (StringUtils.isBlank(appId)) {
			result.setFailMessage("参数错误");
			return result;
		}
		if (endDate == 0)
			endDate = System.currentTimeMillis();
		if (startDate == 0)
			startDate = endDate - 60 * 60 * 1000;
		if (pageSize == 0)
			pageSize = 20;
		int top = 100;
		try {
			page = indicatorLogic.queryTradeErrorCode(appId, nodeId, keyWord, top, startDate, endDate);
			result.pagingHandle(pageSize, pageIndex, page);
		} catch (Exception e) {
			result.setFailMessage(e.getMessage());
		}
		return result;
	}


	@Override
	public PerformanceResult queryTradeErrorStack(String appId, String nodeId, String uri, String errorCode,
			long startDate, long endDate) {
		PerformanceResult result = new PerformanceResult();
		List<PerformanceView> ervs = null;
		if ("NaN".equals(endDate) || "NaN".equals(startDate)) {
			result.setFailMessage("查询时间错误");
			return result;
		}
		if (StringUtils.isBlank(appId)) {
			result.setFailMessage("参数错误");
			return result;
		}
		try {
			ervs = indicatorLogic.queryTradeErrorStacks(appId, nodeId, uri, errorCode, startDate, endDate);
			result.setPerformancesResult(ervs);
		} catch (Exception e) {
			result.setFailMessage(e.getMessage());
		}
		return result;
	}

	@Override
	public IndicatorResult queryTradeErrorStack(String errorId, long startDate, long endDate) {
		IndicatorResult result = new IndicatorResult();
		if ("NaN".equals(endDate) || "NaN".equals(startDate)) {
			result.setFailMessage("查询时间错误");
			return result;
		}
		if (StringUtils.isBlank(errorId)) {
			result.setFailMessage("参数错误");
			return result;
		}
		if (endDate == 0)
			endDate = System.currentTimeMillis();
		if (startDate == 0)
			startDate = endDate - 60 * 60 * 1000;
		try{
			TradeErrorDetail detail = indicatorLogic.getErrorDetail(errorId, startDate, endDate);
			result.setTradeErrorIds(detail);
		} catch(Exception e){
			ExceptionUtils.error(logger, "查询错误信息原始数据出错", e);
        	result.setFailMessage("查询错误信息原始数据出错");
		}
		return result;
	}

	@Override
	public IndicatorResult queryIndicators(String appId, String nodeId, String panelId) {
		IndicatorResult result = new IndicatorResult();
		Service serv = serverLogic.queryServiceById(nodeId);
		IndicatorItem[] items = IndicatorItemManager.getInstance().getNodeIndicatorItems(serv.getId(), 
				serv.getProtocol() == 0 ? serv.getAutoDiscoveryProtocol() : serv.getProtocol(), panelId);
		result.setIndictorItems(items);
		return result;
	}

	@Override
	public IndicatorResult updateResShowIndicator(String targetId, String panelId, List<Integer> metricIds) {
		IndicatorResult result = new IndicatorResult();
		try {
			indicatorLogic.updateResShowIndicator(targetId, panelId, metricIds);
		} catch (Exception e) {
			result.setFailMessage("查找错误明细异常");
			ExceptionUtils.error(logger, "查找错误明细异常", e);
		}
		return result;
	}
	
	@Override
	public PerformanceResult downloadCVSData(HttpServletRequest request, HttpServletResponse response,
			String appId,  String nodeId,
			int menuId, String dataKey,
			String dataId, String keyWord,
			long startDate,  long endDate,
			String orderBy,  boolean desc) throws Exception{
		PerformanceResult result = new PerformanceResult();
        OutputStream outPut = response.getOutputStream();
        L7moduleMenu menu = null;
        String caption = "CsvData";
        try {
        	menu = indicatorLogic.queryL7moduleMenu(menuId);
        	if(menu != null && StringUtils.isNotBlank(menu.getCaption())){
        		caption = menu.getCaption();
        	}
        	response.setContentType("application/vnd.ms-excel;charset=UTF-8");
        	String filename = URLEncoder.encode(caption + ".xls", "UTF-8");
        	if("FF".equals(getBrowser(request))){
        		response.setContentType("application/vnd.ms-excel;charset=ISO-8859-1");
        		filename = new String(filename.getBytes("UTF-8"),"ISO-8859-1");
        	}
        	ApplicationSystem app = appLogic.getApplicationById(appId);
			if(app == null){
				result.setFailMessage("该应用系统不存在");
				return result;
			}
            response.setHeader("Content-Disposition", "attachment; filename=" + filename + ";filename*=UTF-8''" + filename);
            List<MenuColumn> columns = indicatorLogic.queryMenuColumns(menuId); 
            HSSFWorkbook wb = new HSSFWorkbook();  
            HSSFSheet sheet = wb.createSheet(app.getName());
            
            sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, columns.size()-1));
            Cell cell = sheet.createRow((int) 0).createCell(0);
            cell.setCellValue(app.getName() + " " + caption + ".xls");
            cell.setCellStyle(createCellStyle(wb, 1));
            
            sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, columns.size()-1));
            Cell cellt = sheet.createRow((int) 1).createCell(0);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
            cellt.setCellValue(sdf.format(new Date(startDate)) + "-" + sdf.format(new Date(endDate)));
            cellt.setCellStyle(createCellStyle(wb, 2));
            
        	if(columns != null && columns.size() > 0){
        		createCSVHead(sheet, 2, createCellStyle(wb, 3), columns);
        	}
        	List<PerformanceView> perfs = indicatorLogic.queryMenuData(appId, nodeId, menuId, dataKey, dataId, keyWord, 0, 100,
    				startDate, endDate, orderBy, desc);
        	if(perfs != null && perfs.size() > 0){
        		createCSVContent(sheet, 3, createCellStyle(wb, 4), columns, perfs);
        	}
        	wb.write(outPut);
        	outPut.close();
        } catch(Exception e){
        	ExceptionUtils.error(logger, "导出" + caption + "表格出错", e);
        	result.setFailMessage("导出" + caption + "表格出错");
    	}
		return result;
	}
	
	// 以下为服务器端判断客户端浏览器类型的方法  
    private String getBrowser(HttpServletRequest request) {  
        String UserAgent = request.getHeader("USER-AGENT").toLowerCase();  
        if (UserAgent != null) {  
            if (UserAgent.indexOf("msie") >= 0)  
                return "IE";  
            if (UserAgent.indexOf("firefox") >= 0)  
                return "FF";  
            if (UserAgent.indexOf("safari") >= 0)  
                return "SF";  
        }  
        return null;  
    }
    
    /**
	 * 生成单元格样式
	 * @param wb
	 * @param type
	 * @return
	 */
	private HSSFCellStyle createCellStyle(HSSFWorkbook wb, int type){
		HSSFCellStyle style = null;
		switch(type){
			case 1 :
				// 设置标题样式  
				style = wb.createCellStyle();  
				Font fontTitle = wb.createFont();  
				fontTitle.setBoldweight(Font.BOLDWEIGHT_BOLD); // 粗体  
				fontTitle.setFontHeightInPoints((short)20);
				fontTitle.setFontName("黑体");
				style.setFont(fontTitle);  
				style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 水平居中  
				style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中;
				break;
			case 2 : 
				// 设置时间样式  
				style = wb.createCellStyle();  
				Font fontTime = wb.createFont();  
				fontTime.setBoldweight(Font.BOLDWEIGHT_BOLD); // 粗体  
				fontTime.setFontHeightInPoints((short)17);
				style.setFont(fontTime);
				style.setAlignment(HSSFCellStyle.ALIGN_RIGHT); // 水平居右 
				style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
				break;
			case 3 :
				// 设置列名样式  
				style = wb.createCellStyle();  
				style.setWrapText(true);
				style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
				style.setBorderRight(HSSFCellStyle.BORDER_THIN);
				style.setBorderTop(HSSFCellStyle.BORDER_THIN);
				style.setBorderBottom(HSSFCellStyle.BORDER_THIN);  
				Font font_col = wb.createFont();  
				font_col.setBoldweight(Font.BOLDWEIGHT_BOLD); // 粗体  
				font_col.setFontHeightInPoints((short)12);
				style.setFont(font_col);
				style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 水平居中  
				style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
				break;
			default :
				style = wb.createCellStyle();
				style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
				style.setBorderRight(HSSFCellStyle.BORDER_THIN);
				style.setBorderTop(HSSFCellStyle.BORDER_THIN);
				style.setBorderBottom(HSSFCellStyle.BORDER_THIN);  
				Font font_content = wb.createFont();  
				font_content.setFontHeightInPoints((short)12);
				style.setFont(font_content);
				style.setAlignment(HSSFCellStyle.ALIGN_RIGHT); // 水平居右
				style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
		}
		return style;
	}
	
	/**
	 * 生成CSV表头
	 * @param sheet
	 * @param startRow
	 * @param createCellStyle
	 * @param columns
	 */
	private void createCSVHead(HSSFSheet sheet, int startRow, HSSFCellStyle createCellStyle, List<MenuColumn> columns){
		int index = 0;
		Row row = sheet.createRow(startRow);
		row.setHeightInPoints(18);
		for(int i=0; i < columns.size() ; i++){
			Cell cell_i = row.createCell(i);
			if(i == 2){   //时间
				cell_i.setCellValue(columns.get(i).getName() + "(ms)");
			}else{
				cell_i.setCellValue(columns.get(i).getName());
			}
			index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, i, i));
			sheet.setColumnWidth(i, 5000); 
			CellRangeAddress range = sheet.getMergedRegion(index);
			setRegionStyle(sheet, range, createCellStyle);
    	}
	}
	
	/**
	 * 生成CSV内容
	 * @param sheet
	 * @param startRow
	 * @param createCellStyle
	 * @param columns
	 */
	private void createCSVContent(HSSFSheet sheet, int startRow, HSSFCellStyle createCellStyle, List<MenuColumn> columns, List<PerformanceView> perfs){
		int index = 0;
		for(int j=0; j < perfs.size(); j ++){
			Row row = sheet.createRow(startRow);
			row.setHeightInPoints(18);
			for(int i=0;i< columns.size(); i++){
				if(i == 2){    // 时间转换
					Cell cell_i = row.createCell(i);
					if(perfs.get(j).get(columns.get(i).getDataKey()).toString().equals("-")){
						cell_i.setCellValue("-");
					}else{
						double responseTime = Double.valueOf(perfs.get(j).get(columns.get(i).getDataKey()).toString())/1000.0;
						BigDecimal bg = new BigDecimal(responseTime);
						cell_i.setCellValue(String.valueOf(bg.setScale(3, BigDecimal.ROUND_DOWN).doubleValue()));
					}
				} else if(i == 3){  //成功率
					Cell cell_i = row.createCell(i);
					if(perfs.get(j).get(columns.get(i).getDataKey()).toString().equals("-")){
						cell_i.setCellValue("-");
					}else{
						double success_rate = Double.valueOf(perfs.get(j).get(columns.get(i).getDataKey()).toString());
						BigDecimal sr = new BigDecimal(success_rate); 
						cell_i.setCellValue(String.valueOf(sr.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue()));
					}
				} else{
					Cell cell_i = row.createCell(i);
					cell_i.setCellValue(perfs.get(j).get(columns.get(i).getDataKey()).toString());
				}
				index = sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, i, i));
				CellRangeAddress range = sheet.getMergedRegion(index);
				setRegionStyle(sheet, range, createCellStyle);
			}
			startRow ++;
		}
	}
	
	/**
	 * 合并单元格带边框
	 * @param sheet
	 * @param region
	 * @param cs
	 */
	private static void setRegionStyle(HSSFSheet sheet, CellRangeAddress region , HSSFCellStyle cs) {
		for (int i = region.getFirstRow() ; i <= region.getLastRow(); i ++) {
			HSSFRow row = sheet.getRow(i);
			if(row == null){
				row = sheet.createRow(i);
			}
			for (int j = region.getFirstColumn(); j <= region.getLastColumn(); j++) {
				Cell cell = row.getCell(j);
				if(cell == null){
					cell = row.createCell(j);
					cell.setCellValue(" ");
				}
				cell.setCellStyle(cs);
			}
		}
	}
}
